class Complie{
    constructor(el,vm){
        this.$el=document.querySelector(el);
        this.$vm=vm;
        //编译
        if(this.$el){
            // 转换内部内容为片段Fragment
            this.$fragment=this.node2Fragment(this.$el);
            //执行编译
             this.complie(this.$fragment);
            this.$el.appendChild(this.$fragment);
        }
    }
    node2Fragment(el){
        const frag=document.createDocumentFragment();
        let child;
        while((child=el.firstChild)){
             frag.appendChild(child);
        }
        return frag;
    }
    complie(el){
        const childNodes=el.childNodes;
        Array.from(childNodes).forEach(node=>{
            if(this.isElement(node)){
                const noteAtrrs=node.attributes;
                Array.from(noteAtrrs).forEach(attr=>{
                    const attrName=attr.name;//属性名
                    const exp = attr.value; // 属性值
                    //o-text,o-bind,o-click,o-html
                    if(this.isDirective(attrName)){
                        const key=attrName.substring(2);
                        this[key]&&this[key](node,this.$vm,exp);
                    }
                    if(this.isEvent(attrName)){
                        const key=attrName.substring(1);
                        this.eventHandler(node,this.$vm,key,exp)
                    }
                });
            }else if(this.isInterpolation(node)){
                /\{\{(.*)\}\}/.test(node.textContent);
                this.text(node,this.$vm,RegExp.$1);
            }
            if(node.childNodes.length>0){
                this.complie(node);
            }
        });
    }
    isElement(node){
        return node.nodeType===1;
    }
    //插值文本
    isInterpolation(node){
        return node.nodeType===3&&/\{\{(.*)\}\}/.test(node.textContent);
    }
    isDirective(name){
        return name.indexOf("o-")==0;
    }
    isEvent(name){
        return name.indexOf("@")==0;
    }
    text(node,vm,exp){
        this.updata(node,vm,exp,"Text");
    }
    html(node,vm,exp){
        this.updata(node,vm,exp,"Html");
    }
    //双绑
    model(node,vm,exp){
        this.updata(node,vm,exp,"Model");
        node.addEventListener("input",e=>{
            vm[exp]=e.target.value;
        })
    }
    updata(node,vm,exp,dir){
        const updataFn=this["updata"+dir];
        //初始化
        updataFn(node,vm[exp]);
        //依赖收集
        new Watch(vm,exp,function(value){
            updataFn&&updataFn(node,value);
        })
    }
    eventHandler(node,vm,type,method){
        const fn=vm.$options.methods[method];
        node.addEventListener(type,fn.bind(vm));
    }

    updataText(node,text){
        node.textContent=text;
    }
    updataHtml(node,text){
        node.innerHTML=text;
    }
    updataModel(node,text){
        node.value=text;
    }
}